/*
 * UnitTestList.c
 *
 *      Author: marissa
 */

#include <stdio.h>
#include <stdlib.h>

#include "common.h"
#include "Job.h"
#include "Node.h"
#include "List.h"

/* 
 * macro to mimic the functionality of assert() from <assert.h>. The difference is that this version doesn't exit the program entirely.
 * It will just break out of the current function (or test case in this context).
 */
#define myassert(expr) if(!(expr)){ fprintf(stderr, "\t[assertion failed] %s: %s\n", __PRETTY_FUNCTION__, __STRING(expr)); return FALSE; }

ListPtr testlist;

int testCount = 0;
int passCount = 0;

void printTestInfo(char* testName, char *info)
{
	fprintf(stdout, "%s - %s\n", testName, info);
}

void printTestResult(char* testName, Boolean passed)
{
	if(passed == TRUE)
		fprintf(stdout, "%s - %s\n\n", "[PASSED]", testName);
	else
		fprintf(stdout, "%s - %s\n\n", "[FAILED]", testName);
}

NodePtr createTestNode(int jobid)
{
	JobPtr job = createJob(jobid, "cmd args");
	NodePtr node = createNode(job);
	return node;
}

Boolean addAtFrontWithNoNodes()
{
	NodePtr node = createTestNode(1);

	addAtFront(testlist, node);

	myassert(testlist->size == 1)
	myassert(testlist->head == node)
	myassert(testlist->tail == node)
	myassert(testlist->head->next == NULL)
	myassert(testlist->head->prev == NULL)

	return TRUE;
}

Boolean addAtFrontWithOneNode()
{
	printTestInfo("addAtFrontWithOneNode", "(not implemented)");
	
	NodePtr node1 = createTestNode(1);
	addAtFront(testlist, node1);
	
	NodePtr node2 = createTestNode(2);
	addAtFront(testlist, node2);

	myassert(testlist->size == 2)
	myassert(testlist->head == node2)
	myassert(node2->next == node1)
	myassert(node1->prev == node2)
	myassert(testlist->tail == node1)
	myassert(testlist->head->prev == NULL)
	myassert(testlist->tail->next == NULL)
	
	return TRUE;
}

Boolean addAtRearWithNoNodes()
{
	NodePtr node = createTestNode(1);

	addAtRear(testlist, node);

	myassert(testlist->size == 1)
	myassert(testlist->head == node)
	myassert(testlist->tail == node)
	myassert(testlist->head->next == NULL)
	myassert(testlist->head->prev == NULL)

	return TRUE;
}

Boolean addAtRearWithOneNode()
{
	printTestInfo("addAtRearWithOneNode", "(not implemented)");
	NodePtr node1 = createTestNode(1);
	addAtRear(testlist, node1);
	
	NodePtr node2 = createTestNode(2);
	addAtRear(testlist, node2);

	myassert(testlist->size == 2)
	myassert(testlist->head == node1)
	myassert(node1->next == node2)
	myassert(node2->prev == node1)
	myassert(testlist->tail == node2)
	myassert(testlist->head->prev == NULL)
	myassert(testlist->tail->next == NULL)
	
	return TRUE;
}

Boolean removeFromListWithOneNode()
{
	printTestInfo("removeFromListWithOneNode", "(not implemented)");
	NodePtr node1 = createTestNode(1);
	addAtRear(testlist, node1);
	
	removeRear(testlist);
	
	//Now going to do the same thing only at Front instead of rear, just to test the Front functions
	node1 = createTestNode(1); //Have to recreate the node here because removeRear() freed (deleted) the node
	addAtFront(testlist, node1);
	
	removeFront(testlist);

	myassert(testlist->size == 0)
	myassert(testlist->head == NULL)
	myassert(testlist->tail == NULL)
	
	
	return TRUE;
}

Boolean nullNodeTest()
{
	//Not exactly sure what this is supposed to test, but I'm assuming
	//it's supposed to test passing a NULL node to an add/remove function??
	//That's what I'm going to do anyway.
	
	printTestInfo("nullNodeTest", "(not implemented)");
	
	NodePtr node1 = NULL;
	
	addAtFront(testlist, node1);
	addAtRear(testlist, node1);
	removeNode(testlist, node1);
	
	myassert(testlist->size == 0)
	myassert(testlist->head == NULL)
	myassert(testlist->tail == NULL)
	
	
	return TRUE;
}

Boolean removeNodeThatIsNotInListTest() //Test case invented by Louis
{
	//Attempts to remove a node from a list with removeNode()
	//that isn't actually in the list at all.
	
	printTestInfo("removeNodeThatIsNotInListTest", "(not implemented)");
	
	NodePtr node1 = createTestNode(1);
	addAtFront(testlist, node1);
	
	NodePtr node2 = createTestNode(2);
	addAtFront(testlist, node2);
	
	NodePtr node3 = createTestNode(3);
	addAtFront(testlist, node3);
	
	NodePtr node4 = createTestNode(4);	
	
	removeNode(testlist, node4);
	
	myassert(testlist->size == 3)
	myassert(testlist->head == node3)
	myassert(testlist->tail == node1)
	myassert(testlist->head->prev == NULL)
	myassert(testlist->tail->next == NULL)
	myassert(testlist->head->next == node2)
	myassert(testlist->tail->prev == node2)
	
	
	return TRUE;
}

Boolean addAtFrontWhenAlreadyExistsTest() { //Test case invented by Louis
 
    //Attempts to add a node to the list that is already in the list
  
    printTestInfo("addAtFrontWhenAlreadyExistsTest", "(not implemented)");
	
	//Just Populate the list with a few nodes first
	NodePtr node1 = createTestNode(1);
	addAtFront(testlist, node1);
	
	NodePtr node2 = createTestNode(2);
	addAtFront(testlist, node2);
	
	NodePtr node3 = createTestNode(3);
	addAtFront(testlist, node3);
	
	//Now try to add node #2 again
	
	addAtFront(testlist, node2);
	
	myassert(testlist->size == 3)
	myassert(testlist->head == node3)
	myassert(testlist->tail == node1)
	myassert(testlist->head->prev == NULL)
	myassert(testlist->tail->next == NULL)
	myassert(testlist->head->next == node2)
	myassert(testlist->tail->prev == node2)
	
	return TRUE;

}

Boolean addAtRearWhenAlreadyExistsTest() { //Test case invented by Louis
    
    //Attempts to add a node to the list that is already in the list
  
    printTestInfo("addAtRearWhenAlreadyExistsTest", "(not implemented)");
	
	//Just Populate the list with a few nodes first
	NodePtr node1 = createTestNode(1);
	addAtFront(testlist, node1);
	
	NodePtr node2 = createTestNode(2);
	addAtFront(testlist, node2);
	
	NodePtr node3 = createTestNode(3);
	addAtFront(testlist, node3);
	
	//Now try to add node #2 again
	
	addAtRear(testlist, node2);
	
	myassert(testlist->size == 3)
	myassert(testlist->head == node3)
	myassert(testlist->tail == node1)
	myassert(testlist->head->prev == NULL)
	myassert(testlist->tail->next == NULL)
	myassert(testlist->head->next == node2)
	myassert(testlist->tail->prev == node2)
	
	return TRUE;
  

}




void beforeTest(char* testName)
{
	printTestInfo(testName, "Running...");
	testlist = createList();
	testCount++;
}
void afterTest(char* testName, Boolean result)
{
	printTestResult(testName, result);
	freeList(testlist);
	passCount += result;
}
/*
 * etc...
 */

void runUnitTests()
{
	Boolean result;
	char *testName;

	testName = "addAtFrontWithNoNodes";
	beforeTest(testName);
	result = addAtFrontWithNoNodes();
	afterTest(testName, result);

	testName = "addAtFrontWithOneNode";
	beforeTest(testName);
	result = addAtFrontWithOneNode();
	afterTest(testName, result);

	testName = "addAtRearWithNoNodes";
	beforeTest(testName);
	result = addAtRearWithNoNodes();
	afterTest(testName, result);

	testName = "addAtRearWithOneNode";
	beforeTest(testName);
	result = addAtRearWithOneNode();
	afterTest(testName, result);

	testName = "removeFromListWithOneNode";
	beforeTest(testName);
	result = removeFromListWithOneNode();
	afterTest(testName, result);

	testName = "nullNodeTest";
	beforeTest(testName);
	result = nullNodeTest();
	afterTest(testName, result);
	
	//Louis Created the following cases:
	
	testName = "removeNodeThatIsNotInListTest";
	beforeTest(testName);
	result = removeNodeThatIsNotInListTest();
	afterTest(testName, result);
	
	testName = "addAtFrontWhenAlreadyExistsTest";
	beforeTest(testName);
	result = addAtFrontWhenAlreadyExistsTest();
	afterTest(testName, result);
	
	testName = "addAtRearWhenAlreadyExistsTest";
	beforeTest(testName);
	result = addAtRearWhenAlreadyExistsTest();
	afterTest(testName, result);
	
	

	//etc...

	fprintf(stdout, "Test Cases: %d\n",  testCount);
	fprintf(stdout, "Passed: %d\n", passCount);
	fprintf(stdout, "Failed: %d\n", testCount - passCount);
}

int main(int argc, char *argv[])
{
	runUnitTests();
	exit(0);
}
